using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;

namespace Havok
{
    namespace Utilities
    {
        public class HkpMeshBuffer
        {
            public List<Vector3> VertexBuffer = new List<Vector3>();
            public List<short> IndexBuffer = new List<short>();
            public List<int> IndexBuffer32Bit = new List<int>();

            public IndexElementSize IndexSize;
        }

        public class MeshUtilities
        {
            public static List<Vector3> CalculateOverallVertices(Model mdl)
            {
                List<Vector3> vertices = new List<Vector3>();

                foreach (ModelMesh mesh in mdl.Meshes)
                {
                    foreach (ModelMeshPart meshPart in mesh.MeshParts)
                    {
                        int offset = vertices.Count;
                        Vector3[] a = new Vector3[meshPart.NumVertices];

                        mesh.VertexBuffer.GetData<Vector3>(meshPart.StreamOffset + meshPart.BaseVertex * meshPart.VertexStride,
                            a, 0, meshPart.NumVertices, meshPart.VertexStride);

                        Matrix mat = Matrix.Identity;

                        for (int i = 0; i != a.Length; i++)
                        {
                            Vector3.Transform(ref a[i], ref mat, out a[i]);
                        }

                        vertices.AddRange(a);
                    }
                }

                return vertices;
            }

            public static HkpMeshBuffer GetMeshPartMeshBuffer(ModelMesh mesh, int partIndex)
            {
                HkpMeshBuffer meshBuffer = new HkpMeshBuffer();

                switch (mesh.MeshParts[partIndex].VertexStride)
                {
                    case 32:
                        {
                            VertexPositionNormalTexture[] vb = new VertexPositionNormalTexture[mesh.MeshParts[partIndex].NumVertices];
                            mesh.VertexBuffer.GetData<VertexPositionNormalTexture>(vb);

                            foreach (VertexPositionNormalTexture vertex in vb)
                            {
                                meshBuffer.VertexBuffer.Add(vertex.Position);
                            }
                            break;
                        }

                    case 24:
                        {
                            VertexPositionColorTexture[] vb = new VertexPositionColorTexture[mesh.MeshParts[partIndex].NumVertices];
                            mesh.VertexBuffer.GetData<VertexPositionColorTexture>(vb);

                            foreach (VertexPositionColorTexture vertex in vb)
                            {
                                meshBuffer.VertexBuffer.Add(vertex.Position);
                            }
                            break;
                        }

                    case 20:
                        {
                            VertexPositionTexture[] vb = new VertexPositionTexture[mesh.MeshParts[partIndex].NumVertices];
                            mesh.VertexBuffer.GetData<VertexPositionTexture>(vb);

                            foreach (VertexPositionTexture vertex in vb)
                            {
                                meshBuffer.VertexBuffer.Add(vertex.Position);
                            }
                            break;
                        }

                    case 16:
                        {
                            VertexPositionColor[] vb = new VertexPositionColor[mesh.MeshParts[partIndex].NumVertices];
                            mesh.VertexBuffer.GetData<VertexPositionColor>(vb);

                            foreach (VertexPositionColor vertex in vb)
                            {
                                meshBuffer.VertexBuffer.Add(vertex.Position);
                            }
                            break;
                        }
                }

                if (mesh.IndexBuffer.IndexElementSize == IndexElementSize.SixteenBits)
                {
                    meshBuffer.IndexSize = IndexElementSize.SixteenBits;

                    short[] ib = new short[mesh.IndexBuffer.SizeInBytes / sizeof(short)];

                    mesh.IndexBuffer.GetData<short>(mesh.MeshParts[partIndex].StreamOffset, ib, mesh.MeshParts[partIndex].BaseVertex + mesh.MeshParts[partIndex].StartIndex,
                        mesh.IndexBuffer.SizeInBytes / sizeof(short));

                    foreach (short index in ib)
                    {
                        meshBuffer.IndexBuffer.Add(index);
                    }
                }
                else if (mesh.IndexBuffer.IndexElementSize == IndexElementSize.ThirtyTwoBits)
                {
                    meshBuffer.IndexSize = IndexElementSize.ThirtyTwoBits;

                    int[] ib = new int[mesh.IndexBuffer.SizeInBytes / sizeof(int)];

                    mesh.IndexBuffer.GetData<int>(mesh.MeshParts[partIndex].StreamOffset, ib, mesh.MeshParts[partIndex].BaseVertex + mesh.MeshParts[partIndex].StartIndex,
                        mesh.IndexBuffer.SizeInBytes / sizeof(int));

                    foreach (int index in ib)
                    {
                        meshBuffer.IndexBuffer32Bit.Add(index);
                    }
                }
                else
                {
                    throw new Exception("Unknown index format!");
                }

                return meshBuffer;
            }
        }
    }
}
